package org.jflame.commons.convert;

import org.jflame.commons.util.DateHelper;
import org.jflame.commons.util.StringHelper;

import java.sql.Timestamp;
import java.util.Collections;
import java.util.Date;
import java.util.Optional;
import java.util.Set;

import org.apache.commons.lang3.tuple.ImmutablePair;

/**
 * 字符串解析为时间<code>java.util.Date</code>或它的子类java.sql.Date,java.sql.Time,java.sql.Timestamp
 * <p>
 * 如果不指定格式,将尝试使用多种常用格式解析,具体请查看 {@link DateHelper#parseDate(String, Optional, Class)}
 * 
 * @author charles.zhang
 * @param <T> T extends Date
 */
@SuppressWarnings("unchecked")
public class StringToDateConverter<T extends Date> implements StringToObjectConverter<T>, ConvertibleType {

    private final Class<T> targetType;
    private String[] patterns;

    /**
     * 构造函数,默认解析为java.util.Date
     */
    public StringToDateConverter() {
        this((Class<T>) java.util.Date.class, null);
    }

    public StringToDateConverter(String pattern) {
        this((Class<T>) java.util.Date.class, pattern);
    }

    /**
     * 构造函数,指定解析的时间类型
     * 
     * @param targetType 要解析的时间类型
     */
    public StringToDateConverter(Class<T> targetType) {
        this(targetType, null);
    }

    public StringToDateConverter(Class<T> targetType, String pattern) {
        this.targetType = targetType;
        if (StringHelper.isNotEmpty(pattern)) {
            patterns = new String[] { pattern };
        } else {
            if (targetType == java.sql.Date.class) {
                patterns = DateHelper.SHORT_PATTEN;
            } else if (targetType == java.sql.Time.class) {
                patterns = new String[] { DateHelper.HH_mm_ss,DateHelper.HH_mm,DateHelper.CN_HH_mm_ss };
            } else {
                patterns = DateHelper.LONG_PATTEN;
            }
        }
    }

    @Override
    public T convert(String source) {
        if (source == null || source.isEmpty()) {
            return null;
        }

        Date val = DateHelper.parseDate(source, patterns);

        if (targetType == Date.class) {
            return (T) val;
        } else if (targetType == Timestamp.class) {
            return (T) (new Timestamp(val.getTime()));
        } else if (targetType == java.sql.Date.class) {
            return (T) (new java.sql.Date(val.getTime()));
        } else if (targetType == java.sql.Time.class) {
            return (T) (new java.sql.Time(val.getTime()));
        } else {
            throw new ConvertException("String convert to " + targetType.getName() + " is not supported");
        }
    }

    @Override
    public Set<ImmutablePair<Class<?>,Class<?>>> getConvertibleTypes() {
        return Collections.singleton(ImmutablePair.of(String.class, targetType));
    }

}
